/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-12
 * V4.0
 */
package com.jphenix.share.util;

import com.jphenix.standard.docs.ClassInfo;

import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;

/**
 * 处理类加载器工具
 * 
 * 2024-03-27 适配了JDK17
 * 
 * @author 刘虻
 * 2008-1-23下午11:46:29
 */
@ClassInfo({"2024-03-27 21:07","处理类加载器工具"})
public class ClassLoaderUtil {

	//添加扫描途径方法
	protected static Method addURLMethod;

	static {
		try {
			addURLMethod = 
					URLClassLoader.class.getDeclaredMethod(
							"addURL", URL.class);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//设置保护
		addURLMethod.setAccessible(true);
	}

	//系统类加载器
	protected static URLClassLoader systemClassLoader = 
			(URLClassLoader) getSystemClassLoader();

	//扩展类加载器(比系统类加载器更高一级)
	protected static URLClassLoader extClassLoader = 
			(URLClassLoader) getExtClassLoader();


	/**
	 * 获取系统类加载器
	 * @author 刘虻
	 * 2008-1-27下午03:50:02
	 * @return 系统类加载器
	 */
	public static ClassLoader getSystemClassLoader() {
		return ClassLoader.getSystemClassLoader();
	}

	/**
	 * 获取扩展类加载器
	 * @author 刘虻
	 * 2008-1-27下午03:50:23
	 * @return 扩展类加载器
	 */
	public static ClassLoader getExtClassLoader() {
		return getSystemClassLoader().getParent();
	}

	/**
	 * 获取URL类加载器类路径字符串
	 * 刘虻
	 * 2010-8-8 上午10:20:06
	 * @param cl URL类加载器
	 * @return 类路径字符串
	 */
	public static String getURLClassLoaderPath(ClassLoader cl) {
		//类路径数组序列
		ArrayList<URL[]> pathList = new ArrayList<URL[]>();
		getUrlClassLoaderPathUrls(cl,pathList);
		//构造返回值
		StringBuffer reSbf = new StringBuffer();
		for(URL[] urls:pathList) {
			if(urls==null) {
				continue;
			}
			for(int j=0;j<urls.length;j++) {
				reSbf.append(urls[j].getPath()).append(File.pathSeparator);
			}
		}
		return reSbf.toString();
	}

	/**
	 * 获取类加载中的类路径序列
	 * 刘虻
	 * 2010-8-8 上午10:23:19
	 * @param cl URL类加载器
	 * @param pathList 类路径序列
	 */
	public static void getUrlClassLoaderPath(ClassLoader cl,ArrayList<String> pathList) {
		//类路径URL数组序列
		ArrayList<URL[]> pList = new ArrayList<URL[]>();
		getUrlClassLoaderPathUrls(cl,pList); //获取信息
		for(URL[] urls:pList) {
			if(urls==null) {
				continue;
			}
			for(int j=0;j<urls.length;j++) {
				pathList.add(urls[j].getPath());
			}
		}
	}


	/**
	 * 将URL类加载器以及其父类加载器所有的url数组放入序列中(递归函数)
	 * 刘虻
	 * 2010-8-8 上午10:23:19
	 * @param cl URL类加载器
	 * @param pathList 类路径数组序列
	 */
	public static void getUrlClassLoaderPathUrls(ClassLoader cl,ArrayList<URL[]> pathList) {
		if(cl==null) {
			return;
		}
		if(cl instanceof URLClassLoader) {
			pathList.add(((URLClassLoader) cl).getURLs());
			getUrlClassLoaderPathUrls(cl.getParent(),pathList);
		}else {
			return;
		}
	}

	/**
	 * 获取系统类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:54:04
	 * @return 系统类路经数组
	 */
	public static URL[] getSystemURLs() {
		return systemClassLoader.getURLs();
	}


	/**
	 * 获取扩展类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:54:38
	 * @return 扩展类路经数组
	 */
	public static URL[] getExtURLs() {
		return extClassLoader.getURLs();
	}


	/**
	 * 打印类路经
	 * @author 刘虻
	 * 2008-1-27下午03:56:55
	 * @param ps 输出流
	 * @param classPath 类路经数组
	 */
	protected static void list(PrintStream ps, URL[] classPath) {
		for (int i=0; i<classPath.length; i++) {
			ps.println(classPath[i]);
		}
	}

	/**
	 * 打印出系统类路经
	 * @author 刘虻
	 * 2008-1-27下午03:58:33
	 */
	public static void listSystemClassPath() {
		listSystemClassPath(System.out);
	}

	/**
	 * 用指定输出流打印系统类路经
	 * @author 刘虻
	 * 2008-1-27下午03:58:47
	 * @param ps 指定输出流
	 */
	public static void listSystemClassPath(PrintStream ps) {
		ps.println("SystemClassPath:");
		list(ps, getSystemClassPath());
	}

	/**
	 * 获取系统类路径字符串
	 * 刘虻
	 * 2010-4-30 下午01:33:08
	 * @return 系统类路径字符串
	 */
	public static String getSystemClassPathString() {
		//获取类路径url
		URL[] urls = getSystemClassPath();
		//构建返回值
		StringBuffer reSbf = new StringBuffer();
		if(urls!=null) {
			for(int i=0;i<urls.length;i++) {
				reSbf.append(urls[i].getPath()).append(File.pathSeparator);
			}
		}
		return reSbf.toString();
	}

	/**
	 * 打印扩展类路经
	 * @author 刘虻
	 * 2008-1-27下午03:59:08
	 */
	public static void listExtClassPath() {
		listExtClassPath(System.out);
	}

	/**
	 * 用指定输出流输出扩展类路经
	 * @author 刘虻
	 * 2008-1-27下午03:59:22
	 * @param ps 指定输出流
	 */
	public static void listExtClassPath(PrintStream ps) {
		ps.println("ExtClassPath:");
		list(ps, getExtClassPath());
	}

	/**
	 * 获取指定系统类路经数组
	 * @author 刘虻
	 * 2008-1-27下午03:59:59
	 * @return 指定系统类路经数组
	 */
	public static URL[] getSystemClassPath() {
		return getSystemURLs();
	}

	/**
	 * 获取扩展类路经数组
	 * @author 刘虻
	 * 2008-1-27下午04:00:15
	 * @return 扩展类路经数组
	 */
	public static URL[] getExtClassPath() {
		return getExtURLs();
	}

	/**
	 * 加载指定类路经到系统类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:00:27
	 * @param url 指定类路经
	 */
	public static void addURL2SystemClassLoader(URL url) {
		try {
			addURLMethod.invoke(systemClassLoader, url);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加载指定类路经到扩展类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:01:02
	 * @param url 指定类路经
	 */
	public static void addURL2ExtClassLoader(URL url) {
		try {
			addURLMethod.invoke(extClassLoader, url);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 添加类路经到系统类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:01:48
	 * @param path 类路经
	 */
	public static void addClassPath(String path) {
		addClassPath(new File(path));
	}

	/**
	 * 添加类路经到扩展类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:02:09
	 * @param path 类路经
	 */
	public static void addExtClassPath(String path) {
		addExtClassPath(new File(path));
	}

	/**
	 * 添加类类路经到系统类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:02:45
	 * @param dirOrJar 路经文件对象
	 */
	@SuppressWarnings("deprecation")
	public static void addClassPath(File dirOrJar) {
		try {
			addURL2SystemClassLoader(dirOrJar.toURL());
		} catch (MalformedURLException e) {
		}
	}

	/**
	 * 添加指定类路经到扩展类加载器中
	 * @author 刘虻
	 * 2008-1-27下午04:03:19
	 * @param dirOrJar 路经文件对象
	 */
	@SuppressWarnings("deprecation")
	public static void addExtClassPath(File dirOrJar) {
		try {
			addURL2ExtClassLoader(dirOrJar.toURL());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}


	/**
	 * 向当前类加载器中放入新的类路径
	 * 刘虻
	 * 2010-8-8 上午10:45:43
	 * @param path 类路径
	 */
	@SuppressWarnings("deprecation")
	public static void addUrl(String path) {
		try {
			addUrl((new File(path)).toURL());
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 向当前类加载器中放入新的类路径
	 * 刘虻
	 * 2010-8-8 上午11:05:19
	 * @param url 类路径
	 */
	public static void addUrl(URL url) {
		if(!(ClassLoaderUtil.class.getClassLoader() instanceof URLClassLoader)) {
			return;
		}
		try {
			//获取方法
			Method addUrls = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
			addUrls.setAccessible(true); //设置保护
			addUrls.invoke(ClassLoaderUtil.class.getClassLoader(), url);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}
